﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using H2.Streams;
using H2.DataTypes;

namespace Mystery
{
    public class AISquad
    {
        public const int Offset = 352;
        public const int ChunkSize = 116;

        public string Name;

        public uint Flags;

        public short TeamDesignator;

        public short NormalSpawnCount;
        public short LegendarySpawnCount;

        public enum MajorUpgradeOptions
        {
            Normal = 0,
            Few = 1,
            Many = 2,
            None = 3,
            All = 4,
        }
        public MajorUpgradeOptions MajorUpgrade;

        public short VehicleIndex;
        public StringID VehicleVariant;

        public short InitalZoneIndex;
        
        public bool Ignore = true;
        public bool Remove = false;
        public int NetgameBaseTeam = -1;
        public bool NetgameHill = false;

        public StartingLocation[] StartingLocations;

        public class StartingLocation
        {
            public const int ChunkSize = 100;

            public float PositionX;
            public float PositionY;
            public float PositionZ;

            public float RotationYaw;
            public float RotationPitch;
        }

        public static AISquad[] Read(MapStream map, int scnrOffset)
        {
            AISquad[] squads = new AISquad[map.ReadReflexiveAt(scnrOffset + Offset)];
            
            int startOffset = (int)map.Position;
            for (int s = 0; s < squads.Length; s++)
            {
                int chunkOffset = startOffset + s * ChunkSize;
                map.Position = chunkOffset;

                AISquad squad = new AISquad();
                squads[s] = squad;

                squad.Name = map.ReadString(32, true);

                squad.Flags = map.ReadUInt32At(chunkOffset + 32, false);

                squad.TeamDesignator = map.ReadInt16At(chunkOffset + 36, false);

                squad.NormalSpawnCount = map.ReadInt16At(chunkOffset + 44, false);
                squad.LegendarySpawnCount = map.ReadInt16();
                squad.MajorUpgrade = (MajorUpgradeOptions)map.ReadInt16();

                squad.VehicleIndex = map.ReadInt16At(chunkOffset + 52, false);
                squad.VehicleVariant = map.ReadStringIDAt(chunkOffset + 68, false);

                squad.StartingLocations = new StartingLocation[map.ReadReflexiveAt(chunkOffset + 72)];
                int startingLocationsStartOffset = (int)map.Position;
                for (int l = 0; l < squad.StartingLocations.Length; l++)
                {
                    map.Position = startingLocationsStartOffset + l * StartingLocation.ChunkSize;
                    map.Position += 4;

                    StartingLocation startingLocation = new StartingLocation();
                    squad.StartingLocations[l] = startingLocation;

                    startingLocation.PositionX = map.ReadFloat();
                    startingLocation.PositionY = map.ReadFloat();
                    startingLocation.PositionZ = map.ReadFloat();

                    map.Position += 4;

                    startingLocation.RotationYaw = map.ReadFloat();
                    startingLocation.RotationPitch = map.ReadFloat();
                }
            }

            return squads;
        }

        public static void SetDifficulty(AISquad[] squads, int difficulty, bool enableAllSpawns, bool respawnEnabled, bool majorUpgrade)
        {
            for (int s = 0; s < squads.Length; s++)
            {
                AISquad squad = squads[s];

                if (respawnEnabled)
                    squad.Flags |= 128;

                if (enableAllSpawns)
                {
                    squad.NormalSpawnCount = (short)squad.StartingLocations.Length;
                    squad.LegendarySpawnCount = (short)squad.StartingLocations.Length;
                }
                else
                {
                    short spawnCount = (short)squad.StartingLocations.Length;
                    switch (difficulty)
                    {
                        case 0:
                        case 1:
                            spawnCount = squad.NormalSpawnCount;
                            break;
                        case 2:
                            spawnCount = (short)(squad.NormalSpawnCount + ((squad.LegendarySpawnCount - squad.NormalSpawnCount) / 2));
                            break;
                        default:
                            spawnCount = squad.LegendarySpawnCount;
                            break;
                    }

                    squad.NormalSpawnCount = spawnCount;
                    squad.LegendarySpawnCount = spawnCount;
                }

                if (majorUpgrade)
                    squad.MajorUpgrade = MajorUpgradeOptions.Many;
            }
        }

        public static void Write(MapStream map, int scnrOffset, AISquad[] squads)
        {
            map.ReadReflexiveAt(scnrOffset + Offset);

            int startOffset = (int)map.Position;
            for (int s = 0; s < squads.Length; s++)
            {
                int chunkOffset = startOffset + (s * ChunkSize);
                
                AISquad squad = squads[s];
                if (squad.Remove)
                {
                    map.Position = chunkOffset + 72;
                    map.Write(0);
                    continue;
                }

                map.WriteAt(chunkOffset + 32, squad.Flags, false);

                map.WriteAt(chunkOffset + 36, squad.TeamDesignator, false);

                map.WriteAt(chunkOffset + 44, squad.NormalSpawnCount, false);
                map.Write(squad.LegendarySpawnCount);
                map.Write((short)squad.MajorUpgrade);

                map.WriteAt(chunkOffset + 52, squad.VehicleIndex, false);
                map.WriteAt(chunkOffset + 68, squad.VehicleVariant, false);
            }
        }

        public override string ToString()
        {
            return string.Format("{0}{1} Convert To Spawn:[{2}]  Remove:[{3}]  Team Base:[{4}]  Hill:[{5}]", Name, new string(' ', Math.Max(32 - Name.Length, 0)), (Ignore) ? " " : "x", (Remove) ? "x" : " ", NetgameBaseTeam, (NetgameHill) ? "x" : " ");
        }
    }
}
